package com.hjq.mallorder.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.hjq.common.constants.CartConstants;
import com.hjq.common.constants.OrderConstants;
import com.hjq.common.entity.to.SeckillTO;
import com.hjq.common.entity.vo.UserAccountVO;
import com.hjq.common.utils.R;
import com.hjq.mallorder.dao.OrderItemDao;
import com.hjq.mallorder.entity.OrderItemEntity;
import com.hjq.mallorder.entity.PaymentInfoEntity;
import com.hjq.mallorder.entity.to.MemberAddrTO;
import com.hjq.mallorder.entity.to.OrderSubmitTO;
import com.hjq.mallorder.entity.to.SpuInfoTO;
import com.hjq.mallorder.entity.vo.*;
import com.hjq.mallorder.enume.OrderStatusEnum;
import com.hjq.mallorder.feign.CartFeign;
import com.hjq.mallorder.feign.MemberFeign;
import com.hjq.mallorder.feign.ProductFeign;
import com.hjq.mallorder.feign.WareFeign;
import com.hjq.mallorder.interceptor.OrderInterceptor;
import com.hjq.mallorder.service.OrderItemService;
import com.hjq.mallorder.service.PaymentInfoService;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hjq.common.utils.PageUtils;
import com.hjq.common.utils.Query;

import com.hjq.mallorder.dao.OrderDao;
import com.hjq.mallorder.entity.OrderEntity;
import com.hjq.mallorder.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

import static io.lettuce.core.GeoArgs.Unit.m;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    @Autowired
    MemberFeign memberFeign;
    @Autowired
    CartFeign cartFeign;
    @Autowired
    ThreadPoolExecutor executor;
    @Autowired
    StringRedisTemplate template;
    @Autowired
    WareFeign wareFeign;
    @Autowired
    ProductFeign productFeign;
    @Autowired
    OrderItemService orderItemService;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    PaymentInfoService paymentInfoService;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    @RabbitListener(queues = {})
    public void receiveMsg() {

    }

    @Override
    public OrderConfirmVO getOrder() {
        UserAccountVO userAccountVO = OrderInterceptor.threadLocal.get();
        Long memberId = userAccountVO.getId();
        OrderConfirmVO orderConfirmVO = new OrderConfirmVO();
        //防止多线程导致的session丢失问题，再各个线程中共享一下
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //设置地址
        CompletableFuture<Void> addrFuture = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberRecieveEntity> memberRecieveEntities = memberFeign.addrInfo(memberId);
            orderConfirmVO.setAddress(memberRecieveEntities);
        }, executor);

        //获取cart信息
        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<OrderItemVO> currentUserCart = cartFeign.getCurrentUserCart(memberId);
            orderConfirmVO.setItems(currentUserCart);
        }, executor);

        //积分
        CompletableFuture<Void> integrationFuture = CompletableFuture.runAsync(() -> {
            orderConfirmVO.setIntegration(userAccountVO.getIntegration());
        }, executor);
        try {
            CompletableFuture.allOf(addrFuture,cartFuture,integrationFuture).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        //防虫令牌
        String token = UUID.randomUUID().toString().replace("-", "");
        template.opsForValue().set(OrderConstants.ORDER_TOKEN+userAccountVO.getId(),token,30, TimeUnit.MINUTES);
        orderConfirmVO.setOrderToken(token);

        orderConfirmVO.setTotal(orderConfirmVO.getTotal());
        orderConfirmVO.setPayPrice();
        return orderConfirmVO;
    }

    /**
     * 处里订单的提交
     * @param orderSubmitVO
     * @return
     */
    @Transactional
    @Override
    public OrderResponseVO submitOrder(OrderSubmitVO orderSubmitVO) {
        OrderResponseVO responseVO=new OrderResponseVO();
        UserAccountVO userAccountVO = OrderInterceptor.threadLocal.get();
        Long memberId = userAccountVO.getId();
        String script="if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        //1.验证令牌
        String orderToken = orderSubmitVO.getOrderToken();
        Long response = template.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(OrderConstants.ORDER_TOKEN + memberId), orderToken);
        if(response==0L){
            //验证失败
            responseVO.setCode(1);
            return responseVO;
        }
        //2.下单逻辑
        //验价
        OrderSubmitTO orderSubmitTO = createOrder(orderSubmitVO);
        BigDecimal payAmount = orderSubmitTO.getOrder().getPayAmount();
        BigDecimal payPrice = orderSubmitVO.getPayPrice();
        if(Math.abs(payAmount.subtract(payPrice).doubleValue())<0.02){
            //验价成功
            //保存订单
            saveOrder(orderSubmitTO);
            responseVO.setOrderEntity(orderSubmitTO.getOrder());
            //TODO 锁定库存方法
            responseVO.setCode(0);
            //TODO 订单创建成功后需要给Rabbit发消息
            rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",responseVO.getOrderEntity());
        }
        else{
            //验价失败
            responseVO.setCode(2);

        }

        return responseVO;


    }

    @Override
    public void closeOrder(OrderEntity orderEntity) {
        //查询状态
        OrderEntity byId = getById(orderEntity.getId());
        if(byId.getStatus()==OrderStatusEnum.CREATE_NEW.getCode()){
            //如果是待付款，则关单
            OrderEntity orderEntity1 = new OrderEntity();
            orderEntity1.setId(byId.getId());
            orderEntity1.setStatus(OrderStatusEnum.CANCLED.getCode());
            this.updateById(orderEntity1);
        }

    }

    @Override
    public PayVo getOrderByOrderSn(String orderSn) {

        OrderEntity order_sn = getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        List<OrderItemEntity> order_sn1 = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
        String subject = order_sn1.get(0).getSkuName();
        PayVo payVo = new PayVo();
        payVo.setOut_trade_no(orderSn);
        String totalAmount = order_sn.getPayAmount().setScale(2, BigDecimal.ROUND_FLOOR).toString();
        payVo.setTotal_amount(totalAmount);
        payVo.setBody(subject);
        payVo.setSubject(subject);
        return  payVo;
    }

    @Override
    public PageUtils queryPageWithItems(Map<String, Object> params) {
        UserAccountVO userAccountVO = OrderInterceptor.threadLocal.get();
        Long id = userAccountVO.getId();
        QueryWrapper<OrderEntity> orderEntity = new QueryWrapper<OrderEntity>().eq("member_id", id).orderByAsc("order_sn");

        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                orderEntity

        );
        List<OrderEntity> order_sn = page.getRecords().stream().map(item -> {
            String orderSn = item.getOrderSn();
            List<OrderItemEntity> orderItemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
            item.setOrderItemEntities(orderItemEntities);
            return item;
        }).collect(Collectors.toList());
        page.setRecords(order_sn);

        return new PageUtils(page);
    }

    /**
     * 处理支付请求结果
     * @param payAsyncVo
     * @return
     */
    @Override
    public String handleResult(PayAsyncVo payAsyncVo) {
        //保存交易流水
        PaymentInfoEntity paymentInfoEntity = new PaymentInfoEntity();
        paymentInfoEntity.setAlipayTradeNo(payAsyncVo.getTrade_no());
        paymentInfoEntity.setOrderSn(payAsyncVo.getOut_trade_no());
        paymentInfoEntity.setPaymentStatus(payAsyncVo.getTrade_status());
        paymentInfoEntity.setCallbackTime(payAsyncVo.getNotify_time());
        paymentInfoService.save(paymentInfoEntity);

        if("TRADE_SUCCESS".equals(paymentInfoEntity.getPaymentStatus())||"TRADE_FINISHED".equals(paymentInfoEntity.getPaymentStatus())){
            String orderSn = payAsyncVo.getOut_trade_no();
            this.updatOrderStatus(orderSn,OrderStatusEnum.PAYED.getCode());
            return "success";
        }else {
            return  "failed";
        }



    }

    public void updatOrderStatus(String orderSn, Integer code) {
        baseMapper.updatOrderStatus(orderSn,code);
    }

    @Override
    public void createSeckill(SeckillTO seckillTO) {
        //创建订单
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(seckillTO.getOrderSn());
        orderEntity.setMemberId(seckillTO.getMemberId());
        List<MemberRecieveEntity> memberRecieveEntities = memberFeign.addrInfo(seckillTO.getMemberId());
        MemberRecieveEntity memberAddrTO = memberRecieveEntities.stream().filter(entity ->
                entity.getDefaultStatus() == 0
        ).collect(Collectors.toList()).get(0);
        setAddr(orderEntity, memberAddrTO.getCity(), memberAddrTO.getDetailAddress(), memberAddrTO.getName(), memberAddrTO.getPhone(), memberAddrTO.getPostCode(), memberAddrTO.getProvince(), memberAddrTO.getRegion());

        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        orderEntity.setPayAmount(seckillTO.getSeckillPrice().multiply(seckillTO.getSeckillCount()));
        save(orderEntity);

        //创建订单项
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setOrderSn(seckillTO.getOrderSn());
        orderItemEntity.setRealAmount(seckillTO.getSeckillPrice().multiply(seckillTO.getSeckillCount()));
        orderItemEntity.setSkuQuantity(seckillTO.getSeckillCount().intValue());
        //spu信息
        Long skuId = seckillTO.getSkuId();
        R info = productFeign.getSpuInfoBySkuId(skuId);
        String string = JSON.toJSONString(info.get("data"));
        SpuInfoTO spuInfoTO = JSON.parseObject(string, SpuInfoTO.class);
        String brand = (String)info.get("brand");
        orderItemEntity.setSpuId(spuInfoTO.getId());
        orderItemEntity.setSpuName(spuInfoTO.getSpuName());
        orderItemEntity.setSpuBrand(brand);
        orderItemEntity.setCategoryId(spuInfoTO.getCatalogId());
        //sku信息
        orderItemService.save(orderItemEntity);




    }

    private void setAddr(OrderEntity orderEntity, String city, String detailAddress, String name, String phone, String postCode, String province, String region) {
        orderEntity.setReceiverCity(city);
        orderEntity.setReceiverDetailAddress(detailAddress);
        orderEntity.setReceiverName(name);
        orderEntity.setReceiverPhone(phone);
        orderEntity.setReceiverPostCode(postCode);
        orderEntity.setReceiverProvince(province);
        orderEntity.setReceiverRegion(region);
    }

    /**
     * 保存订单数据
     * @param orderSubmitTO
     */
    private void saveOrder(OrderSubmitTO orderSubmitTO) {
        //订单
        OrderEntity order = orderSubmitTO.getOrder();
        order.setModifyTime(new Date());
        this.save(order);
        //订单项
        List<OrderItemEntity> orderItems = orderSubmitTO.getOrderItems();
        orderItemService.saveBatch(orderItems);


    }

    private OrderSubmitTO createOrder(OrderSubmitVO orderSubmitVO){
        OrderSubmitTO orderSubmitTO = new OrderSubmitTO();
        //设置订单信息
        OrderEntity orderEntity = setOrderEntityAddr(orderSubmitVO);
        String orderSn = orderEntity.getOrderSn();
        //3.设置所有订单想
        List<OrderItemEntity> orderItemVOS = setOrderItems(orderSn);

        //设置价格与积分相关信息
        computePrice(orderEntity,orderItemVOS);
        //保存信息
        orderSubmitTO.setOrder(orderEntity);
        orderSubmitTO.setOrderItems(orderItemVOS);
        return  orderSubmitTO;
    }

    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemVOS) {
        BigDecimal sum = new BigDecimal("0.0");
        BigDecimal coupon= new BigDecimal("0.0");
        BigDecimal integration= new BigDecimal("0.0");
        BigDecimal promotion= new BigDecimal("0.0");
        Integer integrationGrowth= 0;
        Integer growth= 0;

        //订单价格相关
        //订单总额
        for (OrderItemEntity itemVO : orderItemVOS) {
            BigDecimal realAmount = itemVO.getRealAmount();
            sum=sum.add(realAmount);
            //优惠
            BigDecimal couponAmount = itemVO.getCouponAmount();
            coupon=coupon.add(couponAmount);
            BigDecimal promotionAmount = itemVO.getPromotionAmount();
            promotion=promotion.add(promotionAmount);
            BigDecimal integrationAmount = itemVO.getIntegrationAmount();
            integration=integration.add(integrationAmount);
            //成长值和积分
            Integer integra = itemVO.getGiftIntegration();
            integrationGrowth=integrationGrowth+integra;
            Integer eachgrowth = itemVO.getGiftGrowth();
            growth= growth+eachgrowth;
        }
        orderEntity.setTotalAmount(sum);
        orderEntity.setCouponAmount(coupon);
        orderEntity.setPromotionAmount(promotion);
        orderEntity.setIntegrationAmount(integration);
        //应付总额
        orderEntity.setPayAmount(sum.add(orderEntity.getFreightAmount()));
        //成长值
        orderEntity.setIntegration(integrationGrowth);
        orderEntity.setGrowth(growth);
        //删除状态
        orderEntity.setDeleteStatus(0);//为删除状态





    }

    private List<OrderItemEntity> setOrderItems(String orderSn) {
        List<OrderItemVO> currentUserCart = cartFeign.getCurrentUserCart(1L);
        List<OrderItemEntity> orderItemEntities=new ArrayList<>();
        if(currentUserCart!=null &&currentUserCart.size()>0){

            orderItemEntities = currentUserCart.stream().map(orderItemVO -> {
                OrderItemEntity order = buildOrderItem(orderItemVO);
                order.setOrderSn(orderSn);

                return order;

            }).collect(Collectors.toList());
        }
        return orderItemEntities;
    }

    private OrderEntity setOrderEntityAddr(OrderSubmitVO orderSubmitVO) {
        UserAccountVO userAccountVO = OrderInterceptor.threadLocal.get();
        String timeId = IdWorker.getTimeId();
        //设置订单信息
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setMemberId(userAccountVO.getId());
        orderEntity.setOrderSn(timeId);
        R fare = wareFeign.getFare(orderSubmitVO.getAddrId());
        String string1 = JSON.toJSONString(fare.get("data"));
        BigDecimal fareMoney =JSON.parseObject(string1,BigDecimal.class);
        Object addr = fare.get("addr");
        String string = JSON.toJSONString(addr);
        MemberAddrTO memberAddrTO = JSON.parseObject(string, MemberAddrTO.class);
        orderEntity.setFreightAmount(fareMoney);
        setAddr(orderEntity, memberAddrTO.getCity(), memberAddrTO.getDetailAddress(), memberAddrTO.getName(), memberAddrTO.getPhone(), memberAddrTO.getPostCode(), memberAddrTO.getProvince(), memberAddrTO.getRegion());
        //设置订单状态
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        orderEntity.setAutoConfirmDay(7);
        return orderEntity;
    }

    private OrderItemEntity buildOrderItem(OrderItemVO orderItemVO) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        //订单信息
        //spuInfo
        Long skuId = orderItemVO.getSkuId();
        R info = productFeign.getSpuInfoBySkuId(skuId);
        String string = JSON.toJSONString(info.get("data"));
        SpuInfoTO spuInfoTO = JSON.parseObject(string, SpuInfoTO.class);
        String brand = (String)info.get("brand");
        orderItemEntity.setSpuId(spuInfoTO.getId());
        orderItemEntity.setSpuName(spuInfoTO.getSpuName());
        orderItemEntity.setSpuBrand(brand);
        orderItemEntity.setCategoryId(spuInfoTO.getCatalogId());
        //skuInfo
        orderItemEntity.setSkuName(orderItemVO.getSkuTitle());
        orderItemEntity.setSkuId(skuId);
        orderItemEntity.setSkuPic(orderItemVO.getImage());
        orderItemEntity.setSkuPrice(orderItemVO.getPrice());
        String skuAttrs = StringUtils.join(orderItemVO.getSkuAttrs(), ";");
        orderItemEntity.setSkuAttrsVals(skuAttrs);
        orderItemEntity.setSkuQuantity(orderItemVO.getCount());
        //优惠忽略

        //积分
        orderItemEntity.setGiftGrowth(orderItemVO.getPrice().multiply(new BigDecimal(orderItemVO.getCount())).intValue());
        orderItemEntity.setGiftIntegration(orderItemVO.getPrice().multiply(new BigDecimal(orderItemVO.getCount())).intValue());
        //订单的价格信息
        orderItemEntity.setPromotionAmount(new BigDecimal(0));
        orderItemEntity.setIntegrationAmount(new BigDecimal(0));
        orderItemEntity.setCouponAmount(new BigDecimal(0));
        BigDecimal origin = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity()));
        orderItemEntity.setRealAmount(origin.subtract( orderItemEntity.getPromotionAmount()).subtract( orderItemEntity.getIntegrationAmount()).subtract( orderItemEntity.getCouponAmount()));
        return  orderItemEntity;

    }

}